Schematic execution flow

The following table shows the program flow when a WHDLoad installed program will be executed. I hope it helps to understand how WHDLoad works and how WHDLoad, the Slave and the installed program does cooperate.

The USER
  • starts the demo or game by clicking a Icon or by starting WHDLoad via the command line
The Operating System
  • loads the WHDLoad executable and starts it
WHDLoad
  • checks the Software and Hardware environment
  • loads and checks the Slave
  • allocates required memory for the installed program
  • if PreLoad/S is enabled it loads disk images and files into the RAM (as far as free memory is available)
  • switches OS off (disables mutitasking and interrupts, degrades graphics hardware to OCS, inits all hardware with defined values)
  • jumps into Slave
Slave
  • loads the main executable of the installed program by calling a WHDLoad function (e.g. resload_DiskLoad or resload_LoadFile)
  • patches the main executable (that the program will load his data via the Slave, to fix compatibility problems, to enable an exit from the program)
  • calls the main executable
Installed program
  • will do his stuff
  • on loading data from disk it will call the Slave (because the Slave has patched it in this way previously), and the Slave will call WHDLoad, and WHDLoad will partial enable the OS to load the data (only if the datas are not PreLoad'ed), then return, return and the installed program continues
The USER
  • exits the program by pressing the QuitKey
Slave
WHDLoad
  • reenables the OS (restores hardware registers, display and memory)
  • frees all allocated resources
  • returns to the OS

How to install a simple one disk trackloader

This is a very small and short step by step guide on how to create an install using WHDLoad. The guide reflects an ideal simple case. In the real such a case will probably never occure. For special cases and problems read also the chapters following this.
  1. Prework

  2. The Slave

    To write the slave we need following informations:

    1. Where on disk is the main executable located ?
    2. Where inside the main executable is the disk loader located ?
    To get these informations we first analyze the bootblock. Most times the main executable will loaded from here via exec.DoIO(). Sometimes a special trackloader is in the bootblock. We now write a Slave which will simulates the bootblock and loads the main executable from the disk image. Now we rip the main executable from the image or a memory dump. After that we have to find the loader in the main exe. An fast way is to search for the pattern $AAAAAAAA (used by MFM decoding) with a hex-editor. Then cut the area (+/- $1000 bytes) found, disassemble it, and search the start of the routine. Understand the parameterlist. Now we create code for the Slave which will patch this loader routine, in a way that all calls to the loader will be redirect to the Slave. The Salve will then adjust the parameters and call the WHDLoad function resload_DiskLoad.

  3. In the ideal case the install is now complete.

    Only left to do is to create a nice Icon. Rip two pictures using a Freezer or U.A.E. and build the Icon. The 16 color RomIcon palette is recommend.

Possible problems and special cases

Non standard trackloader

Some programs use a very own disk format. With the result, that DIC is unable to create the disk images. In this case you have two choices. First, you write a parameter file for The Patcher which will create the images (or files) from the original disks, or second you use WHDLoad itself for this operation.
The Patcher is the prefered way. The advantages when using the The Patcher are: runs fully in multitasking, supports DF0: - DF3:, is debugable with every Debugger. For more informations on how to program the The Patcher study the examples in the Src directory and refer to the documentation of The Patcher
Using WHDLoad itself to get the data off the original disks is also possible. You have to write a special Install.Slave which does this job. This Install.Slave should load the original load routine via resload_DiskLoadDev. After some perhaps required modifications on the original load routine the Slave uses it to load the datas from the nonstandard tracks and writes the data using resload_SaveFile. Some times the loaders are unable to read a whole disk or you will have to less memory, in this case let the Install.Slave create smaller files (10 cyls for example). And later join the files using "C:Join".

Multiple disks

If the program uses more than one disk the slave must redirect the disk accesses to the appropriate image file. Sometimes this is not easy. Some programs support more than one drive, so you can use the drive number for selecting the disk. Most programs use an id on every disk to distinguish them. In this case use a variable which holds the disk number, and on every access to the disk id (determinate such a access by analyzing the parameters for the disk loader) increase the variable (if last disk reached decrease). So hopefully the loader will read the id again and again up the right disk is inserted. Perhaps there is an request from the program that the user should insert the right disk, disable it.

Highscore saving

Not much to say here. Use resload_SaveFile to write the appropriate memory area to the disk. If you like encrypt it a bit that not everybody can patch it to easy. It is not recommend to write directly into disk images (using resload_SaveFileOffset), because if someting goes wrong (e.g. crash) it's possible that the images will be damaged.

Savegames

Savegame handling is the same as with highscores.

Accesses to the operating system

At the time the slave and the installed program is executed absolutely no OS exist nor is accessible nor makes any sense to access them ! Therefore all accesses which the installed program like to do, must be disabled. If there are less of them, and without function in the WHDLoad environment (like exec.Disable() or exec.SuperState()) simple $4e71 them. If the accesses have an important function (like exec.DoIo()), redirect them to the slave and emulate them. If there are a more of them, create an simple exec.library in an unused memory area (set $4 to this). (Example Oscar.slave emulates exec.AllocMem()) To detect such accesses the initial execbase is set to $f0000001 with the intention that all routines which like to use the execbase will force an "Address Error" exception.

Common compatibility problems

Limited address space on 68000/68010/68ec020

On these processors the address space is limited to 16MB ($000000...$ffffff) because these CPU's have only 24 address lines. As a result all accesses to higher spaces are performed to the lower 16MB and the most signifikant 8 bits are ignored. Some programs use these bits to store any data, or simple forgets to clear these. On a processor with full 4 GB address space like 68020/680ec30/68030/68040/68060 this will not work, because the full 32bit address will be accessed.
To solve this you have to patch these accesses and redirect them to the appropriate address. Different stackframes on each processor The stackframes created by the processor on interrupts and exceptions are different for the members of the 68k family. On the 68000 a stackframe is 6 byte, except on Bus and Address Error. The stackframe contains first the saved SR at (a7) and the saved PC at (2,a7). On all other processors (68010+) the minimal stackframe is 8 byte and contains additional the vector number as word at (6,a7). This Four-Word stackframe format $0 is created for "Trap #xx" and Interrupts on 68010-68060. The stackframes on other exceptions are different on each processor. The RTE instruction works different on the 68000 against 68010+. On a 68000 it simply restores the SR and PC and continue program execution at the interrupted address. On the 68010+ it will additional frees the stackframe depending on the stackframe format.
Some programs are pushing an address (PC) and a SR and then execute a RTE instruction. This works on a 68000 only, on 68010+ this will have undefinable results.
If a program do so, you have to fix this stuff. Sometimes it may be enough to replace the RTE with a RTR.

MOVEM.x RL,-(An) on 68000/010 and 68020/030/040

There is a difference if the register used in predecrement mode is also contained in the register list. For the 68020, 68030 and 68040 the value written to memory is the initial register value decemented by the size of the operation. The 68000 and 68010 write the initial register value (not decremented).
Because such a construction is not very useful no software software is known which has problems because this.

General guidelines for writing installs

Tips & tricks

What's better, using diskimages or files ?

Sometimes you will have the choice to use disk images or real files. Both has advantages. The use of disk images is most time the easier and faster way to create the slave. But real files are better cacheable (if there is less memory or the memory is fragmented diskimages cannot be cached). The needed space on harddisk will also smaller with real files than with disk images. Only if there are a lot of files (more than 30) you should use disk images.